/*
 *  Copyright 2013 Utkin Dmitry
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#ifndef PROTOQTRPC_BLOCKINGCLOSURE_H
#define PROTOQTRPC_BLOCKINGCLOSURE_H

#include <QtGlobal>
#include <google/protobuf/stubs/common.h>

// TODO: use protobuf logger


namespace protoqtrpc
{

class BlockingClosurePrivate;

/**
 * @brief blocks calling thread until closure is runned
 */
class BlockingClosure: public ::google::protobuf::Closure
{
public:
    /**
     * @brief Constructs blocking closure
     */
    BlockingClosure();

    /**
     * @brief Destroys blocking closure
     */
    virtual ~BlockingClosure();

    /**
     * @brief Starts closure and unblock waiting thread
     *  @sa wait()
     */
    virtual void Run();

    /**
     * @brief Blocks thread until Run is called
     *  if Run() was already called, this function returns immediately
     *  @sa Run()
     * @param time maximum time in milliseconds, if time = 0 then wait will never timeout
     * @return true - Run() was called, false - timeout
     */
    bool wait(unsigned long time = 30000);

    /**
     * @brief Run() has been called?
     *  @sa Run()
     * @return if Run has been called this function returns true, else it returns false
     */
    bool hasRun() const;

    /**
     * @brief resets closure to initial state so that it may be reused in
     * a new call. Must not be called while an RPC is in progress.
     */
    void reset();

private:
    Q_DECLARE_PRIVATE(BlockingClosure)
    Q_DISABLE_COPY(BlockingClosure)
    BlockingClosurePrivate* d_ptr;
};

}

#endif
